package com.aaa.controller;

import com.aaa.entity.UserLogin;
import com.aaa.result.Result;
import com.aaa.service.UserLoginService;
import com.aaa.vo.LoginVO;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/auth")
public class AuthController {
    //注入jedis连接对象工厂，用来制造redis对象
    @Autowired
    private JedisConnectionFactory factory;

    @Autowired
    private UserLoginService service;

    //可以拿到请求过来的地址和设备
    @Autowired
    private HttpServletRequest request;

    //


    @PostMapping("/login")
    public Result login(@RequestBody @Validated LoginVO info){


        try {
            //获取主体
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(info.getUsername(), info.getPassword());
            subject.login(usernamePasswordToken);

            // 生成jwt    token
            // 获取当前请求的 发起人地址192.168.22.93
            // 获取当前请求的 设备
            // 发送请求的设备 必须有固定的请求头
            int m=30;
            Date date = new Date(System.currentTimeMillis() + 1000 * 60 * m);//过期时间
            Algorithm secret = Algorithm.HMAC256("secret"); //secret 相当于盐值  密令
            String token = JWT.create()
                    .withExpiresAt(date)   //设置token过期时间
                    .sign(secret);         //设置签名
            //通过jedis对象获取redis对象
            RedisConnection connection = factory.getConnection();
            //将token转换成bytes数组
            byte[] key = token.getBytes();

            HashMap<Object, Object> map = new HashMap<>();
            //登录用户的ip地址  将来用于 比对验证用户 是否还是这个ip
            map.put("ipaddr",request.getRemoteHost());
            //将当前登陆的用户信息存起来（与token绑定）
            map.put("userinfo",subject.getPrincipal());
            //将拿到的ip地址的map转换成byte数组
            byte[] value = new JdkSerializationRedisSerializer().serialize(map);
            //将数据存储到redis中
            connection.set(key,value);
            connection.close();
            //登陆成功，把token返回过去，前端再取出来token 放在cookie中
            return Result.success(token);

        } catch (UnknownAccountException e) {
            return Result.error("账号没找到");
        }catch (LockedAccountException e) {
            return Result.error("当前账号已被冻结");
        }catch (IncorrectCredentialsException e) {
            return Result.error("密码不正确");
        }catch (AuthenticationException e) {
            return Result.error("程序员正在搬砖中");
        }

    }

    //验证token(鉴权)
    @GetMapping("/authToken")
    public Result authToken(@NotBlank(message = "需要传递token") @Validated String authToken,@NotBlank(message = "需要传递tip") @Validated String ipAddr){
        try {

            System.out.println("================="+ipAddr);
            //加密对象
            Algorithm algorithm = Algorithm.HMAC256("secret");
            JWTVerifier verifier = JWT.require(algorithm).build();
            //将token进行加密
            DecodedJWT jwt = verifier.verify(authToken);
            //获取redis连接对象
            RedisConnection connection = factory.getConnection();
            //通过token取当时存储的信息
            byte[] bytes = connection.get(authToken.getBytes());
            if(bytes.length == 0){
                return  Result.error("token不存在");
            }
            //如果有 将存储的东西拿出来进行反序列化
            Map<String,String> map = (Map) new JdkSerializationRedisSerializer().deserialize(bytes);
            //拿到当时认证的时候存储的ip地址
            String userAddr = map.get("ipaddr");
            //当时存储的ip地址和现在请求的ip地址判断是否token是否被盗用
            if( ! ipAddr.equals(userAddr) ){
                return  Result.error("面签者 有问题！");
            }

        }catch (Exception e){
            return  Result.error("not ok");
        }

        return Result.success("ok");
    }

    @GetMapping("/haha")
    public Result tset(){
        return Result.success("测试");
    }

    @GetMapping("/getPer")
    public Result getPer(@NotBlank(message = "需要传递token") @Validated String authToken){
        //根据token拿到对应的数据
        RedisConnection connection = factory.getConnection();
        byte[] bytes = connection.get(authToken.getBytes());
        Map<String,Object> map = (Map) new JdkSerializationRedisSerializer().deserialize(bytes);

        if (map !=null){
            UserLogin userinfo = (UserLogin) map.get("userinfo");
            String username = userinfo.getUsername();
            Result result = service.queryPermissionsByLoginUserName(username);
            return result;
        }
        return Result.error("token已经过期");
    }


}
